[PHP][Yii] ActiveQueryのandWhereとandFilterWhereの違いを整理してみた
まいどです
CX事業本部の中安です。
今回の記事は自分の備忘録として、YiiFramework の ActiveQuery
の andWhere
と andFilterWhere
の違いを簡単にまとめます。
ActiveQuery上の定義
andWhere
、andFilterWhere
両メソッドは、クエリの条件(Where)文を連想配列によって追加するメソッドになります。
まずはこれが何処に定義されているかですが、下記のように 親クラスのQuery
が実装するQueryTrait
上に存在しています。
Query → QueryTrait ↑ ActiveQuery
両メソッドのドキュメントはこちらになります。
andWhere()
https://www.yiiframework.com/doc/api/2.0/yii-db-querytrait#andWhere()-detailandFilterWhere()
https://www.yiiframework.com/doc/api/2.0/yii-db-querytrait#andFilterWhere()-detail
説明の違い
andWhere()
の説明はこちらになります。
Adds an additional WHERE condition to the existing one. The new condition and the existing one will be joined using the `AND` operator.
すでに存在している条件に追加のWHERE条件を足します。新しい条件は既存の条件と「AND」演算子を用いて結合されます。
続いてandFilterWhere()
の説明です。
Adds an additional WHERE condition to the existing one but ignores empty operands. The new condition and the existing one will be joined using the 'AND' operator.
This method is similar to andWhere(). The main difference is that this method will remove empty query operands. As a result, this method is best suited for building query conditions based on filter values entered by users.
すでに存在している条件に追加のWHERE条件を足しますが、空のオペランドは無視します。新しい条件は既存の条件と「AND」演算子を用いて結合されます。
このメソッドは andWhere() に似ています。主な違いは空のクエリオペランドは削除するということです。その結果、このメソッドはユーザによって入力されたフィルタ値に基づいてクエリ条件を構築するのに最適です。
両メソッドとも説明はすごく似ていますが、一箇所違いがありますね。
太字で書いている「空のオペランドは無視する」というのが大きな違いのようです。 では「空のオペランド」とはどういうことでしょうか。
これは同じく QueryTrait
に定義されている isEmpty
というメソッドに影響されるようです。
isEmpty
の説明を見てみると
Returns a value indicating whether the give value is "empty".
The value is considered "empty", if one of the following conditions is satisfied:- it is null
- an empty string
- a string containing only whitespace characters
- or an empty array指定した値が「空」かどうかを示す値を返します。
次の条件のいずれかが満たされている場合、値は「空」とみなされます。- NULL
- 空の文字列
- 空白文字のみを含む文字列
- または空の配列
この条件に当てはまると Where文として追加されないということです。
PHP標準のempty
関数とは仕様が違うので注意が必要そうです。
挙動を比べてみる
ActiveQueryオブジェクトを呼び出して、直接コマンドオブジェクトを作って生のSQL文を出力してみます。
$query = User::find() ->andWhere(['name' => 'なかやす']) ->andFilterWhere(['name' => 'なかやす']); echo $query->createCommand()->rawSql;
これを実行すると
SELECT * FROM `user` WHERE (`name`='なかやす') AND (`name`='なかやす')
(※注意: 本来は出力は改行されませんが、読みやすいように改行しています)
同じ条件が2つ並んでしまいますが、期待値としては正解です。
では、空文字列を条件にしてみます。
$query = User::find() ->andWhere(['name' => '']) ->andFilterWhere(['name' => '']); echo $query->createCommand()->rawSql;
これを実行すると
SELECT * FROM `user` WHERE (`name`='なかやす')
条件が1つだけになります。andFilterWhere
に与えた条件が空文字だったので無視されたわけです。
まとめ
andFilterWhere
はandWhere
と違って、条件の値が NULL、空文字列(空白スペースだけも空文字列扱い)、空配列の場合は無視をする- PHP標準の
empry
とは異なり、0
やfalse
は「空」扱いではない - 非必須入力項目で空文字チェックをする必要がないので便利だが、仕様を間違って把握しているとバグの温床になりやすいの注意
といったところでしょうか。
どなたかの役に立てば幸いでございます。